﻿Shader "Hidden/Universal Render Pipeline/Blur"
{
    Properties
    {
        _MainTex("Source", 2D) = "white" {}
    }

    HLSLINCLUDE

	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
	#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
	#include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
	#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
 
	TEXTURE2D(_MainTex);		SAMPLER(sampler_MainTex);

	float4 _MainTex_TexelSize;
	half4 _Gradient;
	half4 _GoldenRot;
	half4 _Params;
	half _StepOffset;
	
	#define _Offset _Gradient.xy
	#define _AreaSize _Gradient.z
	#define _SmoothWidth _Gradient.w
	#define _Iteration _Params.x
	#define _Radius _Params.y
	#define _PixelSize _Params.zw
	
	// Tranforms position from object to homogenous space
	inline float4 UnityObjectToClipPos(in float3 pos)
	{
	#if defined(STEREO_CUBEMAP_RENDER_ON)
		return UnityObjectToClipPosODS(pos);
	#else
		// More efficient than computing M*VP matrix product
		return mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(pos, 1.0)));
	#endif
	}
	inline float4 UnityObjectToClipPos(float4 pos) // overload for float4; avoids "implicit truncation" warning for existing shaders
	{
		return UnityObjectToClipPos(pos.xyz);
	}

	inline half SmoothCircle(half2 center, half radius, half smoothWidth, half2 uv)
	{
		return smoothstep(radius - smoothWidth, radius, distance(uv, center));
	}

	half Mask(half2 uv)
	{
		//half2 center = (uv * 2.0 - 1.0) + _Offset; // [0,1] -> [-1,1] 
		//return dot(center, center) * _AreaSize;
		half2 center = _Offset;
		uv = uv * 2.0 - 1.0;
		uv = uv * half2(_ScreenParams.x / _ScreenParams.y, 1);
		return SmoothCircle(center, _AreaSize, _SmoothWidth, uv);
	}
	
	half4 FragPreview(Varyings i): SV_Target
	{
		half2 uv = i.texcoord;
		return Mask(i.texcoord);
	}

	struct Attributes1
	{
		float4 positionOS       : POSITION;
		float2 uv               : TEXCOORD0;
		UNITY_VERTEX_INPUT_INSTANCE_ID
	};

	Varyings Vert1(Attributes1 input)
	{
		Varyings output;
		UNITY_SETUP_INSTANCE_ID(input);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); 

		output.positionCS = UnityObjectToClipPos(input.positionOS);
    	output.texcoord = input.uv;
		
		return output;
	}

	half4 Frag(Varyings i): SV_Target
	{
		half mask = Mask(i.texcoord);
		half2 res = _MainTex_TexelSize.xy * mask;
        half j = _StepOffset;
        half4 col;                
        col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
        col.rgb += SAMPLE_TEXTURE2D( _MainTex, sampler_MainTex, i.texcoord + half2(j, j) * res).rgb;
        col.rgb += SAMPLE_TEXTURE2D( _MainTex, sampler_MainTex, i.texcoord + half2(j, -j) * res).rgb;
        col.rgb += SAMPLE_TEXTURE2D( _MainTex, sampler_MainTex, i.texcoord + half2(-j, j) * res).rgb;
        col.rgb += SAMPLE_TEXTURE2D( _MainTex, sampler_MainTex, i.texcoord + half2(-j, -j) * res).rgb;
        col.rgb *= 0.2; 
		return col;
	}
	
	half4 Frag2(Varyings i): SV_Target
	{
		half2x2 rot = half2x2(_GoldenRot);
		half4 accumulator = 0.0;
		half4 divisor = 0.0;

		half2 uv = i.texcoord;

		half r = 1.0;
		half2 angle = half2(0.0, _Radius * saturate(Mask(uv)));
		UNITY_LOOP
        for (int j = 0; j < _Iteration; j++)
		{
			r += 1.0 / r;
			angle = mul(rot, angle);
			half4 bokeh = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, half2(uv + _PixelSize * (r - 1.0) * angle));
			accumulator += bokeh * bokeh;
			divisor += bokeh;
		}
		return accumulator / divisor;
	}
 
    ENDHLSL
 
    SubShader
    {
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
		ZTest Always ZWrite Off Cull Off

		Pass
		{
			Name "Blur0"
			HLSLPROGRAM
			
			#pragma vertex Vert1
			#pragma fragment Frag
			
			ENDHLSL
			
		}
		
		// Pass 1 - Preview
		Pass
		{
			HLSLPROGRAM
			
			#pragma vertex Vert1
			#pragma fragment FragPreview
			
			ENDHLSL
			
		}
    }
}